package com.booway.threadtemp.factoryimpl;

import com.booway.threadtemp.exception.FactoryException;
import com.personal.core.queueextend.IplugBlockingDueue;
import com.personal.core.queueextend.PluggableLinkedBlockingDueue;

/**
 * 原料产品抽象工厂
 * 可插队实现
 * 该实现在队列式工厂的基础上实现了队列的插队操作
 * @author cuibo
 *
 */
public abstract class AbstractPluggableFactory<S, P> extends AbstractFactory<S, P>
{

    public AbstractPluggableFactory()
    {
        super();
    }
    
    public AbstractPluggableFactory(int maxSyncCount)
    {
        super(maxSyncCount);
    }
    
    /**
     * 添加原料到工厂
     * @param index
     * @param entry
     * @return
     * @throws FactoryException
     */
    public synchronized boolean addStock(int index, S entry) throws FactoryException
    {
        this.worker.checkStock(entry);
        this.worker.checkCanWork();
        return addStockNoCheck(index, entry);
    }
    
    /**
     * 添加原料到工厂
     * @param coordinate
     * @param entry
     * @return
     * @throws FactoryException
     */
    public synchronized boolean addStockBefore(S coordinate, S entry) throws FactoryException
    {
        this.worker.checkStock(entry);
        this.worker.checkCanWork();
        return addStockBeforeNoCheck(coordinate, entry);
    }
    
    /**
     * 添加原料到工厂
     * @param coordinate
     * @param entry
     * @return
     * @throws FactoryException
     */
    public synchronized boolean addStockAfter(S coordinate, S entry) throws FactoryException
    {
        this.worker.checkStock(entry);
        this.worker.checkCanWork();
        return addStockAfterNoCheck(coordinate, entry);
    }
    
    /**
     * 移除添加原料
     * @param index
     * @param entry
     * @return
     */
    public S removeStock(int index)
    {
        return getCurrentQueue().remove(index);
    }
    
    /**
     * 原料顺序交换
     * @param paramOne
     * @param paramTwo
     * @return
     */
    public boolean exchange(S paramOne, S paramTwo)
    {
    	return getCurrentQueue().exchange(paramOne, paramTwo);
    }
    
    /**
     * 原料顺序交换
     * @param indexOne
     * @param indexTwo
     * @return
     */
    public boolean exchange(int indexOne, int indexTwo)
    {
    	return getCurrentQueue().exchange(indexOne, indexTwo);
    }
    
    /**
     * 将entry移动到coordinate前面
     * @param indexOne
     * @param indexTwo
     * @return
     */
    public boolean moveBefore(S entry, S coordinate)
    {
        return getCurrentQueue().moveBefore(entry, coordinate);
    }
    
    /**
     * 将entry移动到coordinate后面
     * @param indexOne
     * @param indexTwo
     * @return
     */
    public boolean moveAfter(S entry, S coordinate)
    {
        return getCurrentQueue().moveAfter(entry, coordinate);
    }
    
    private boolean addStockNoCheck(int index, S entry)
    {
        if (getCurrentQueue().add(index, entry))
        {
            this.worker.addStockLatch(entry);
            return true;
        }
        return false;
    }
    
    private boolean addStockBeforeNoCheck(S coordinate, S entry)
    {
        if (getCurrentQueue().addBefore(coordinate, entry))
        {
            this.worker.addStockLatch(entry);
            return true;
        }
        return false;
    }
    
    private boolean addStockAfterNoCheck(S coordinate, S entry)
    {
        if (getCurrentQueue().addAfter(coordinate, entry))
        {
            this.worker.addStockLatch(entry);
            return true;
        }
        return false;
    }
    
    private IplugBlockingDueue<S> getCurrentQueue()
    {
        return (IplugBlockingDueue<S>) stockQueue;
    }
    

    @Override
    protected void initQueueTypeAndResource()
    {
        stockQueue = new PluggableLinkedBlockingDueue<S>();
    }

    @Override
    protected S getNextStock() throws InterruptedException
    {
        return stockQueue.take();
    }
    
    
}

